// strings包与字符串操作
package main

import (
	"fmt"
	"strings"
)

func test1() {
	//strings.Builder有一个内容容器，是一个byte类型的切片（字节切片），底层数组是一个字节数组，都是通过一个unsafe.Pointer类型的字段指向了底层字节数组的指针值。
	var builder1 strings.Builder
	builder1.WriteString("你好")
	builder1.Write([]byte{'A', 'B', 'C'})
	fmt.Println(builder1.String(), builder1.Cap(), builder1.Len()) //你好ABC 16 9

	//手动扩容的容量是原容器容量的二倍再加上n
	builder1.Grow(10)
	fmt.Println(builder1.String(), builder1.Cap(), builder1.Len()) //你好ABC 42 9

	//如果在strings.Builder的副本上调用strings.Builder的任意方法都会引发 panic
	builder3 := builder1
	// builder3.Grow(1) // 这里会引发 panic: strings: illegal use of non-zero Builder copied by value
	_ = builder3

	//使用Reset方法可以让Builder值重新回到零值状态
	builder1.Reset()
	fmt.Println(builder1.String(), builder1.Cap(), builder1.Len()) // 0 0

	//可以通过任何方式复制Builder的指针值，这样的指针值指向的都是同一个Builder值。
	f2 := func(bp *strings.Builder) {
		(*bp).Grow(1) // 这里虽然不会引发 panic，但不是并发安全的。
		builder4 := *bp
		//builder4.Grow(1) // 这里会引发 panic。
		_ = builder4
	}
	f2(&builder1)

	//如果Builder值被多方同时操作，那么其中的内容就很可能会出现操作冲突和并发安全问题。
	ch1 := make(chan strings.Builder, 1)
	ch1 <- builder1
	builder2 := <-ch1
	//builder2.Grow(1) // 这里会引发panic
	_ = builder2

	//可以先使用再传递，只要在传递之前调用它的Reset方法即可
	builder1.Reset()
	builder5 := builder1
	builder5.Grow(1) // 这里不会引发 panic。
}
func test2() {
	//strings.Reader类型的值可以高效地读取字符串，在读取的过程中会保存已读取字节的计数，已读计数就是下一次读取的起始索引位置。
	// 示例1
	reader1 := strings.NewReader("你好ABC")
	fmt.Printf("%d,%d\n", reader1.Len(), reader1.Size()) //9,9

	buf1 := make([]byte, 47)
	n, _ := reader1.Read(buf1)
	fmt.Printf("%d,%d,%d\n", n, reader1.Len(), reader1.Size()) //9,0,9

	// 示例2
	buf2 := make([]byte, 21)
	offset1 := int64(64)
	n, _ = reader1.ReadAt(buf2, offset1)
	fmt.Printf("%d,%d,%d,%d\n", n, offset1, reader1.Len(), reader1.Size()) //0,64,0,9
}
func main() {
	test1()
	test2()
}
